package com.xpec.c4.service.common;

import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jgroups.Address;

import com.xpec.c4.codec.CodecUtility;
import com.xpec.c4.game.utility.GUID;
import com.xpec.c4.game.utility.GameUtility;
import com.xpec.c4.message.MessageTypes;
import com.xpec.c4.service.group.ServerGroup;
import com.xpec.c4.service.ioc.AOPMethodInterceptor;
import com.xpec.c4.service.module.BasicServiceModule;
import com.xpec.c4.service.module.ModuleServer;
import com.xpec.c4.service.module.message.ModuleStatus;

/**
 * 消息处理类
 * 
 * @author lipeilin
 * 
 */
public class MessageHandle {
	
	static class MessageCount
	{
		public AtomicInteger bytes = new AtomicInteger();
		public AtomicInteger messages = new AtomicInteger();
	}
	
	/**
	 * 是否进行消息统计
	 */
	private static boolean msgStatisticEnabled = false;
	private static long msgStatisticEnableTime = 0;
	private static long msgStatisticEnablePeriod = 5000;

	/**
	 * 消息计数
	 */
	private static final Map<Integer, MessageCount> msgCounter = new ConcurrentHashMap<Integer, MessageCount>();
	
	
	/**
	 * Log管理器
	 */
	private static final Log log = LogFactory.getLog(MessageHandle.class);

	/**
	 * Action调用前台的处理
	 */
	private static AOPMethodInterceptor aop = null;
	
	private static ModuleServer moduleServer = null;
	
	/**
	 * 
	 * @param _aop
	 */
	public static void setAOP(AOPMethodInterceptor _aop) {
		aop = _aop;
	}

	/**
	 * 
	 * @param moduleServer
	 */
	public static void setModuleServer(ModuleServer moduleServer) {
		MessageHandle.moduleServer = moduleServer;
	}

	/**
	 * 
	 * @return
	 */
	public static ModuleServer getModuleServer() {
		return moduleServer;
	}

	/**
	 * 处理消息请求
	 * 
	 * @param messageType
	 * @param messageContent
	 * @param sessionID
	 * @return
	 * @throws IllegalAccessException
	 * @throws InvocationTargetException
	 * 
	 * @author lipeilin
	 * @2011-3-11 下午12:16:31
	 */
	public static Object handleMessage(
			int messageType,
			int syncId,
			byte[] messageContentBytes,
			GUID sessionID,
			String moduleID,
			String srcService,
			Address address)
					throws IllegalAccessException, InvocationTargetException 
	{
		// 做消息统计
		if(msgStatisticEnabled)
		{
			if(System.currentTimeMillis() - msgStatisticEnableTime > msgStatisticEnablePeriod)
			{
				msgStatisticEnabled = false;
			}	
				
			MessageCount c = msgCounter.get(messageType);
			if(c == null)
			{
				c = new MessageCount();
				msgCounter.put(messageType, c);
			}
			c.messages.incrementAndGet();
			c.bytes.addAndGet(messageContentBytes.length);
		}

		// 處理 module 控制相關消息
		if (handleModuleControlMessage(syncId, messageType, messageContentBytes, address)) {
			// 消息有被處理過就不繼續往下走
			return null;
		}

		// 發到指定的模塊
		if(moduleID != null){
			
			BasicServiceModule bsm = moduleServer.getBasicServiceModule(moduleID);
		
			if(bsm == null){
				log.error("module is not exist! moduleID:"+ moduleID 
						+ " messageType:" + messageType
						+ " sessionID:" + sessionID
						+ " srcService:" + srcService
						);
				return null;
			}

			bsm.addMessage(messageType, syncId, messageContentBytes, sessionID, srcService, address, 0);			
		}		
		// 群發
		else{
			
			List<BasicServiceModule> modules = new ArrayList<BasicServiceModule>(moduleServer.getAllModules());
			
			if(modules != null){
				
				for(BasicServiceModule it : modules){
					it.addMessage(messageType, syncId, messageContentBytes, sessionID, srcService, address, 0);
				}
				
			}
			
		}
		return null;
	}

	/**
	 * 處理 module 控制相關消息
	 * 
	 * @param messageType
	 *            消息類型
	 * @param messageContentBytes
	 *            消息內容 (還沒decode)
	 * @return 如果傳入的消息有被處理 return true<br>
	 *         沒有處理 return false
	 */
	public static boolean handleModuleControlMessage(int syncId, int messageType, byte[] messageContentBytes,
			Address address) {
		switch (messageType) {
		case MessageTypes.S_MODULE_SHUTDOWN_MODULE: {
			// 取得 module name
			String moduleId = (String) CodecUtility.decodeByte(messageContentBytes);

			if (moduleId == null) {
				if (log.isErrorEnabled()) {
					log.error(GameUtility.getCurMethodName() + ": shutdown module fail, moduleId=null");
				}
				return true;
			}

			// 關
			ModuleServer.getInstance().shutdownModule(moduleId);
			return true;
		}

		case MessageTypes.S_MODULE_RESTART_MODULE: {
			// 取得 module name
			String moduleId = (String) CodecUtility.decodeByte(messageContentBytes);

			if (moduleId == null) {
				if (log.isErrorEnabled()) {
					log.error(GameUtility.getCurMethodName() + ": restart module fail, moduleId=null");
				}
				return true;
			}

			// 開
			ModuleServer.getInstance().restartModule(moduleId);
			return true;
		}

		case MessageTypes.S_MODULE_GET_ALL_MODULE_LIST: {
			// 取得本地 module 狀態列表
			ArrayList<ModuleStatus> moduleStatusList = ServerGroup.getTransportManager()
					.getLocalModuleStatusList();

			ServerGroup.getTransportManager().sendResponse(address, syncId, moduleStatusList);
			return true;
		}

		} // switch (messageType) {

		return false;
	}

	public static void enableMsgStatistic()
	{
		if(!msgStatisticEnabled)
		{
			msgStatisticEnabled = true;
			msgStatisticEnableTime = System.currentTimeMillis();
			msgCounter.clear();
		}
	}

	public static String printMessageStat() 
	{
		StringBuilder sb = new StringBuilder();
		sb.append("printMessageStat:\n");
		for(Integer key : msgCounter.keySet())
		{
			MessageCount c = msgCounter.get(key);
			sb.append(key).append(" => ").append("m: " + c.messages.get()).append(" b:"+ c.bytes.get() + "\n");
		}
		return sb.toString();
	}
}
